home *** CD-ROM | disk | FTP | other *** search
-
- #import "EMErrorManager.h"
- #import "EMErrorObserver.h"
- #import "EMErrorDescription.h"
- #import "EMObjcErrorCatcher.h"
- #import "localizable_strings.h"
- #import <appkit/appkit.h>
-
- #define ALIGNMENT(type) (offsetof(struct { char c; type t; },t))
-
- @implementation EMErrorManager
-
- static id theEMErrorManager = nil;
-
- //--------------------------------------------------------------------------------
- // HILFSFUNKTIONEN
- // Die ErrorReporter und -handler Funktionen, SignalHandler
- //--------------------------------------------------------------------------------
-
- static void EMErrorReporter(NXHandler *errorState)
- {
- EMErrorInfo *ex=(id)errorState->data1;
-
- NXLogError("EMErrorReporter: %s: #%d\n",[ex location],[ex code]);
- }
-
-
- static void EMErrorHandler(NXHandler *errorState)
- {
- if(![[EMErrorManager new] handle:EMInfoObjectForHandler(errorState)])
- NXDefaultTopLevelErrorHandler(errorState);
- }
-
-
- static void EMSignalHandler(int signalno)
- {
- sigsetmask(0); // unblock all signals...
- EM_ERROR(EM_SIGBASE+signalno,NULL,NULL);
- }
-
-
- //--------------------------------------------------------------------------------
- // HILFSFUNKTIONEN, Teil 2
- //--------------------------------------------------------------------------------
-
- EMErrorInfo *EMInfoObjectForHandler(NXHandler *errorState)
- {
- EMErrorInfo *exception;
- const struct { @defs(EMErrorInfo) } *eip;
-
- if(errorState->data1!=NULL && (((int)(errorState->data1))%ALIGNMENT(id))==0 &&
- ((eip=errorState->data1)->code==errorState->code))
- exception=(id)errorState->data1;
- else
- exception=[[EMErrorInfo newWithCode:errorState->code
- userInfo:errorState->data1:errorState->data2] getContext];
- return exception;
- }
-
- // if(errorState->code>=NX_APP_ERROR_BASE &&
- // errorState->code<NX_APP_ERROR_BASE+EM_ERROR_RANGE)
-
- //--------------------------------------------------------------------------------
- // HILFSFUNKTIONEN, Teil 3
- //--------------------------------------------------------------------------------
-
- /*
- static void EMFreeValues(void *val)
- {
- id v=val;
-
- if([v isKindOf:[List class]])
- [v freeObjects];
- [v free];
- }
- */
-
- //--------------------------------------------------------------------------------
- // KLASSENMETHODEN
- // Sicherstellen, dass nur eine Instanz benutzt wird.
- //--------------------------------------------------------------------------------
-
- + new
- {
- if(!theEMErrorManager)
- {
- NXZone *myZone=NXCreateZone(vm_page_size*4,vm_page_size*2,YES);
-
- NXNameZone(myZone,"EMErrorManager");
- theEMErrorManager=self=[[super allocFromZone:myZone] init];
- }
- else
- self=theEMErrorManager;
- return self;
- }
-
-
- //--------------------------------------------------------------------------------
- // INIT & FREE
- //--------------------------------------------------------------------------------
-
- - init;
- {
- [super init];
- [self readErrorDescriptions];
- objectsToNotify=[[HashTable allocFromZone:[self zone]]
- initKeyDesc:"i" valueDesc:"@"];
- [EMObjcErrorCatcher setup];
- [self installErrorReporter:YES];
- [self installErrorHandler:YES];
- [self installSignalHandler:YES];
- return self;
- }
-
-
- - free;
- {
- // [objectsToNotify freeKeys:NULL values:EMFreeValues];
- // allgemeines Porblem: wann duerfen die EMErrorObserver freigegeben werden?
- [objectsToNotify free];
- return [super free];
- }
-
-
- //--------------------------------------------------------------------------------
- // ERROR FILE
- //--------------------------------------------------------------------------------
-
- - readErrorDescriptions;
- {
- return [self readErrorDescriptionsFromBundle:[NXBundle mainBundle]];
- }
-
-
- - readErrorDescriptionsFromBundle:(NXBundle *)bundle;
- {
- char path[MAXPATHLEN+1];
- struct stat buf;
- NXTypedStream *stream;
- int vmajor,vemc;
- HashTable *newTable;
- NXHashState state;
- const void *key;
- EMErrorDescription *ed;
-
- NX_DURING
- [bundle getPath:path forResource:"Errors" ofType:"estore"];
- if(strlen(path)<3)
- NX_RAISE(NX_APP_ERROR_BASE,CANT_LOCATE_MSGS,NULL);
- else if(stat(path,&buf))
- NX_RAISE(NX_APP_ERROR_BASE,CANT_ACCESS_MSGS,NULL);
- else if(!(buf.st_mode && S_IFREG))
- NX_RAISE(NX_APP_ERROR_BASE,CANT_LOCATE_MSGS,NULL);
- stream=NXOpenTypedStreamForFile(path,NX_READONLY);
- NXSetTypedStreamZone(stream,[self zone]);
- NXReadTypes(stream,"ii",&vmajor,&vemc);
- if(vmajor*100+vemc > EM_MAJOR_VERSION*100+EM_EMC_VERSION)
- NX_RAISE(NX_APP_ERROR_BASE,MSG_NEW_VERSION,NULL);
- else if(vmajor*100+vemc < EM_MAJOR_VERSION*100+EM_EMC_VERSION)
- NX_RAISE(NX_APP_ERROR_BASE,MSG_OLD_VERSION,NULL);
- newTable=NXReadObject(stream);
- NXCloseTypedStream(stream);
- if(errorDescriptions==nil)
- errorDescriptions=newTable;
- else
- {
- state=[newTable initState];
- while([newTable nextState:&state key:&key value:(void *)&ed])
- {
- if([errorDescriptions isKey:key])
- NX_RAISE(NX_APP_ERROR_BASE,ERROR_NUMBER_CLASH,NULL);
- [errorDescriptions insertKey:key value:ed];
- }
- [newTable free];
- }
- NX_HANDLER
- if([self errorDescriptionFor:EM_INTBASE+2])
- EM_ERROR(EM_INTBASE+2,NXLocalHandler.data1,NULL);
- else
- {
- NXRunAlertPanel(INTERNAL_ERROR,CANT_LOAD_MESSAGES,QUIT_BUTTON,NULL,NULL,
- NXLocalHandler.data1,EM_MAJOR_VERSION,EM_EMC_VERSION);
- exit(1);
- }
- NX_ENDHANDLER
-
- return self;
- }
-
-
- - (HashTable *)errorDescriptions;
- {
- return errorDescriptions;
- }
-
-
- - (EMErrorDescription *)errorDescriptionFor:(int)code;
- {
- return (EMErrorDescription *)[errorDescriptions valueForKey:(void *)code];
- }
-
-
- //--------------------------------------------------------------------------------
- // Handler (de)installieren
- //--------------------------------------------------------------------------------
-
- - installErrorReporter:(BOOL)flag;
- {
- if(flag)
- NXRegisterErrorReporter(NX_APPBASE,NX_APPBASE+EM_ERROR_RANGE,
- EMErrorReporter);
- else
- NXRemoveErrorReporter(NX_APPBASE);
- return self;
- }
-
-
- - installErrorHandler:(BOOL)flag;
- {
- if(flag)
- NXSetTopLevelErrorHandler(EMErrorHandler);
- else
- NXSetTopLevelErrorHandler(NXDefaultTopLevelErrorHandler);
- return self;
- }
-
-
- - installSignalHandler:(BOOL)flag;
- {
- BOOL signals[]={1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,-1};
- int i;
- void (*handler)(int);
-
- handler=flag?EMSignalHandler:SIG_DFL;
- for (i=0;signals[i]!=-1;i++)
- if(signals[i])
- signal(i,handler);
- return self;
- }
-
-
- //--------------------------------------------------------------------------------
- // Raise Error
- //--------------------------------------------------------------------------------
-
- - raise:infoObject;
- {
- [infoObject getContext];
- switch([[self errorDescriptionFor:[infoObject code]] severity])
- {
- case EMSeverityWarning:
- [self handle:infoObject];
- break;
- case EMSeverityError:
- NX_RAISE([infoObject code],infoObject,NULL);
- break;
- case EMSeverityFatalError:
- [self handle:infoObject];
- exit(2);
- break;
- case EMSeverityUnknown:
- if(([infoObject code])==EM_INTBASE+1)
- {
- NXRunAlertPanel(NULL,NO_UNKNOWN_EVEN,QUIT_BUTTON,NULL,NULL,
- [infoObject codeString]);
- exit(2);
- }
- EM_ERROR(EM_INTBASE+1,(void *)[infoObject code],[infoObject location]);
- break;
- }
- return self;
- }
-
- //--------------------------------------------------------------------------------
- // Fehler behandeln
- //--------------------------------------------------------------------------------
-
- - handle:infoObject;
- {
- id ed=[self errorDescriptionFor:[infoObject code]],
- eo=[objectsToNotify valueForKey:(void *)[infoObject code]];
-
- [self notify:[ed actions] of:infoObject];
- [self notify:eo of:infoObject];
- [NXApp delayedFree:infoObject];
- return ed;
- }
-
-
- //--------------------------------------------------------------------------------
- // Objekte ueber den Fehler benachrichtigen
- //--------------------------------------------------------------------------------
-
- - notify:obj of:infoObject;
- {
- if([obj isKindOf:[List class]])
- [obj makeObjectsPerform:@selector(dispatch:) with:infoObject];
- else
- [obj perform:@selector(dispatch:) with:infoObject];
- return self;
- }
-
-
- //--------------------------------------------------------------------------------
- // Objekte registrieren, die im Fehlerfall benachrichrichtigt werden
- //--------------------------------------------------------------------------------
-
- - addObserver:anObject selector:(SEL)aSel forError:(int)errorNumber;
- {
- return [self addObserver:anObject selector:aSel forErrors:errorNumber:1];
- }
-
-
- - addObserver:anObject selector:(SEL)aSel forErrors:(int)base:(int)count;
- {
- id observer,entry;
- int i;
-
- NX_DURING
- observer=[EMErrorObserver allocFromZone:[self zone]];
- [observer initWith:anObject andSelector:aSel];
- NX_HANDLER
- [observer free];
- NX_RERAISE();
- NX_ENDHANDLER
-
- for(i=base;i<base+count;i++)
- {
- entry=[objectsToNotify valueForKey:(void *)i];
-
- if(!entry)
- [objectsToNotify insertKey:(void *)i value:observer];
- else if(![entry isKindOf:[List class]])
- [objectsToNotify insertKey:(void *)i
- value:[[[[List allocFromZone:[self zone]]
- init] addObject:entry] addObject:observer]];
- else
- [entry addObject:observer];
- }
- return self;
- }
-
-
- - removeObserver:anObject forError:(int)errorNumber
- {
- return [self removeObserver:anObject forErrors:errorNumber:1];
- }
-
-
- - removeObserver:anObject forErrors:(int)base:(int)count;
- {
- id entry;
- int i,j;
-
- for(i=base;i<base+count;i++)
- {
- entry=[objectsToNotify valueForKey:(void *)i];
-
- if(!entry)
- EM_ERROR(EM_INTBASE+12,(void *)i,NULL);
- else if(![entry isKindOf:[List class]])
- if([entry observer]==anObject)
- [objectsToNotify removeKey:(void *)i];
- else
- EM_ERROR(EM_INTBASE+12,(void *)i,NULL);
- else
- {
- for(j=[entry count]-1;j>=0;j--)
- if([[entry objectAt:j] observer]==anObject)
- break;
- if(j>=0)
- {
- [entry removeObjectAt:j];
- if([entry count]<2)
- {
- [objectsToNotify insertKey:(void *)i value:[entry lastObject]];
- [entry free];
- }
- }
- else
- EM_ERROR(EM_INTBASE+12,(void *)i,NULL);
- }
- }
- return self;
- }
-
-
- //--------------------------------------------------------------------------------
- // THAT'S IT
- //--------------------------------------------------------------------------------
-
- @end
-